import smbus

"""设备地址"""
_I2C_ADDR = 0x64
"""寄存器定义"""
_REG_SIZE = 0x18
_REG_SR = 0x00
_REG_CR = 0x01
_REG_Q_MSB = 0x02
_REG_Q_LSB = 0x03
_REG_Q_TH_MSB = 0x04
_REG_Q_TH_LSB = 0x05
_REG_Q_TL_MSB = 0x06
_REG_Q_TL_LSB = 0x07
_REG_V_MSB = 0x08
_REG_V_LSB = 0x09
_REG_V_TH_MSB = 0x0A
_REG_V_TH_LSB = 0x0B
_REG_V_TL_MSB = 0x0C
_REG_V_TL_LSB = 0x0D
_REG_I_MSB = 0x0E
_REG_I_LSB = 0x0F
_REG_I_TH_MSB = 0x10
_REG_I_TH_LSB = 0x11
_REG_I_TL_MSB = 0x12
_REG_I_TL_LSB = 0x13
_REG_T_MSB = 0x14
_REG_T_LSB = 0x15
_REG_T_TH = 0x16
_REG_T_TL = 0x17

"""计算用常量"""
_CQ = 0.340    # mAh
_CV = 70.8     # V
_CI = 64       # mV
_CT = 510      # K

class LTC2944:
    """库仑计LTC2944"""
    mode = 0
    m = 0
    alcc_config = 0
    shutdown = 0
    r_sence = 50

    def __init__(self,bus = 1,R = 50):
        """
        构造方法
        bus     i2c bus number
        R       R_sense (mOhm)
        """
        self.r_sence = R
        self.__bus = smbus.SMBus(bus)
        self.show_status()
        
    def show_status(self):
        """显示状态"""
        SR = self.read_reg(_REG_SR)
        if SR&(1<<6) : print("Current Alert") 
        if SR&(1<<5) : print("Accumulated Charge Overflow/Underflow")
        if SR&(1<<4) : print("Temperature Alert")
        if SR&(1<<3) : print("Charge Alert High")
        if SR&(1<<2) : print("Charge Alert Low")
        if SR&(1<<1) : print("Voltage Alert")
        if SR&(1<<0) : print("Undervoltage Lockout Alert")

        CR = self.read_reg(_REG_CR)
        self.mode = (CR&(0x03<<6))>>6
        if self.mode == 0 : print("Sleep Mode")
        elif self.mode == 1 : print("Manual Mode")
        elif self.mode == 2 : print("Scan Mode")
        else : print("Automatic Mode")

        prescaler_m = (CR&(0x07<<3))>>3
        if prescaler_m < 7 : self.m=pow(4,prescaler_m)
        else : self.m = 4096
        print("Prescaler M",self.m)

        self.alcc_config = (CR&(0x03<<1))>>1
        if self.alcc_config == 0 : print("ALCC Pin: Disabled")
        elif self.alcc_config == 1 : print("ALCC Pin: Charge Complete Mode")
        elif self.alcc_config == 2 : print("ALCC Pin: Alert Mode")
        else : print("ALCC Pin: Not allowed status!")

        self.shutdown = CR&0x01
        if self.shutdown==0 : print("Analog Section Working")
        else : print("Analog Section Shutdown")

    
    def show_measure(self):
        """显示测量值"""
        print("%.3f"%self.get_Q(),"mAh",
        "%.3f"%self.get_V(),"V",
        "%.3f"%self.get_I(),"mA",
        "%.3f"%self.get_T(),"°C")

    def show_threshold(self):
        """显示阈值"""
        print("Q:",self.get_Q_TL(),"mAh","~",self.get_Q_TH(),"mAh")
        print("V:",self.get_V_TL(),"V","~",self.get_V_TH(),"V")
        print("I:",self.get_I_TL()*1000,"mA","~",self.get_I_TH()*1000,"mA")
        print("T:",self.get_T_TL()-273.15,"°C","~",self.get_T_TH()-273.15,"°C")

    def average_power(self,T=10):
        """TODO : 测量一段时间内的平均功耗"""
        power = 0
        return power

    def read_reg(self,addr):
        return self.__bus.read_byte_data(_I2C_ADDR,addr)

    def get_Q(self):
        REG = self.read_reg(_REG_Q_MSB)*256 + self.read_reg(_REG_Q_LSB)
        Q = REG*_CQ*(50/self.r_sence)*(self.m/4096) # mAh
        return Q

    def get_V(self):
        REG = self.read_reg(_REG_V_MSB)*256 + self.read_reg(_REG_V_LSB)
        V = REG*_CV/65535 # V
        return V

    def get_I(self):
        REG = self.read_reg(_REG_I_MSB)*256 + self.read_reg(_REG_I_LSB)
        I = (REG-32767)/32767*_CI/self.r_sence # A
        return I*1000

    def get_T(self):
        REG = self.read_reg(_REG_T_MSB)*256 + self.read_reg(_REG_T_LSB)
        T = REG*_CT/65535 # K
        return T-273.15

    def get_Q_TH(self):
        REG = self.read_reg(_REG_Q_TH_MSB)*256 + self.read_reg(_REG_Q_TH_LSB)
        Q_TH = REG*_CQ*50/self.r_sence*self.m/4096 
        return Q_TH # mAh

    def get_Q_TL(self):
        REG = self.read_reg(_REG_Q_TL_MSB)*256 + self.read_reg(_REG_Q_TL_LSB)
        Q_TL = REG*_CQ*50/self.r_sence*self.m/4096 
        return Q_TL # mAh

    def get_V_TH(self):
        REG = self.read_reg(_REG_V_TH_MSB)*256 + self.read_reg(_REG_V_TH_LSB)
        V_TH = REG*_CV/65535 
        return V_TH # V

    def get_V_TL(self):
        REG = self.read_reg(_REG_V_TL_MSB)*256 + self.read_reg(_REG_V_TL_LSB)
        V_TL = REG*_CV/65535 
        return V_TL # V

    def get_I_TH(self):
        REG = self.read_reg(_REG_I_TH_MSB)*256 + self.read_reg(_REG_I_TH_LSB)
        I_TH = (REG-32767)/32767*_CI/self.r_sence 
        return I_TH # A

    def get_I_TL(self):
        REG = self.read_reg(_REG_I_TL_MSB)*256 + self.read_reg(_REG_I_TL_LSB)
        I_TL = (REG-32767)/32767*_CI/self.r_sence 
        return I_TL # A

    def get_T_TH(self):
        REG = self.read_reg(_REG_T_MSB)*256
        T_TH = REG*_CT/65535 
        return T_TH # K

    def get_T_TL(self):
        REG = self.read_reg(_REG_T_MSB)*256
        T_TL = REG*_CT/65535
        return T_TL # K

    def set_mode(self,mode):
        """
        设置模式
        0：休眠
        1：手动模式
        2：扫描模式
        3：自动模式
        """
        CR = self.__bus.read_byte_data(_I2C_ADDR,_REG_CR)
        CR = CR&~(0x03<<6)
        CR = CR|(mode<<6)
        self.__bus.write_byte_data(_I2C_ADDR,_REG_CR,CR)
        self.mode = mode

    def set_m(self,m):
        """
        设置预分频器m的值
        1、4、16、64、256、1024、4096
        """
        if m == 1 : b = 0
        elif m == 4 : b = 1
        elif m == 16 : b = 2
        elif m == 64 : b = 3
        elif m == 256 : b = 4
        elif m == 1024 : b = 5
        elif m == 4096 : b = 6
        else :
            print("please enter 1/4/16/64/256/1024/4096 !")
            return

        CR = self.__bus.read_byte_data(_I2C_ADDR,_REG_CR)
        CR = CR&~(7<<3)
        CR = CR|(b<<3)
        self.__bus.write_byte_data(_I2C_ADDR,_REG_CR,CR)
        self.m = m

    def set_alcc(self,alcc):
        """
        设置ALCC引脚配置
        0：关闭
        1：充电完成
        2：报警
        """
        CR = self.__bus.read_byte_data(_I2C_ADDR,_REG_CR)
        CR = CR&~(3<<1)
        CR = CR|(alcc<<1)
        self.__bus.write_byte_data(_I2C_ADDR,_REG_CR,CR)
        self.alcc_config = alcc

    def set_shutdown(self,shutdown):
        CR = self.__bus.read_byte_data(_I2C_ADDR,_REG_CR)
        CR = CR&~(1<<0)
        CR = CR|(shutdown<<0)
        self.__bus.write_byte_data(_I2C_ADDR,_REG_CR,CR)
        self.shutdown = shutdown

    def set_Q(self,Q):
        """设置库仑计初值"""
        self.set_shutdown(1)
        REG = abs(int(Q/_CQ/50*self.r_sence/self.m*4096))
        if REG > 0xffff : 
            REG = 0xffff
        self.__bus.write_byte_data(_I2C_ADDR,_REG_Q_MSB,REG>>8)
        self.__bus.write_byte_data(_I2C_ADDR,_REG_Q_LSB,REG&0xff)
        self.set_shutdown(0)

